<?xml version="1.0" encoding="UTF-8"?>
<project name="TeamCityPluginCommon">

  <!--
  Tasks:
                package.teamcity.plugin
                deploy.teamcity.plugin
                undeploy.teamcity.plugin
                unpack.teamcity

  Targets:
                check.teamcitydistribution
  -->

  <property name="path.variable.teamcitydistribution" value="${teamcity.distribution}"/>

  <property name="teamcity.internal.default.out" value="dist"/>


  <macrodef name="package.teamcity.plugin" description="packages TeamCity plugin">
    <attribute name="name" description="name of the plugin"/>
    <attribute name="server.output" default="" description="path to compiled server plugin output"/>
    <attribute name="server.resources" default="" description="path to server plugin web resources to be packed under 'buildServerResources'"/>
    <attribute name="agent.output" default="" description="path to compiled agent plugin output"/>
    <attribute name="common.output" default="" description="path to compiled common plugin output"/>
    <attribute name="out" default="${teamcity.internal.default.out}" description="directory to put prepared plugin zip into"/>
    <attribute name="plugin.descriptor.file" default="${basedir}/teamcity-plugin.xml" description="path to teamcity-plugin.xml file"/>
    <attribute name="common.jar.name" default="@{name}-common.jar" description="name of the shared jar between server and agent"/>
    <attribute name="out.unpacked" default="@{out}/unpacked"
               description="name of the directory to store unpacked plugin (not packed into zip)"/>

    <attribute name="server.lib.dir" default="" description="directory to get libs for the server part"/>
    <attribute name="server.lib.includes" default="none should match" description="includes pattern of the files in the directory"/>
    <attribute name="plugin.version" default="SNAPSHOT"
               description="the version of the plugin to put into teamcity-plugin.xml instead of '@version@'"/>

    <element name="server-additional-files" optional="yes" description="fileset of the files to pack into root of the server plugin part"/>
    <element name="agent-additional-files" optional="yes" description="fileset of the files to pack into root of the agent plugin part"/>

    <sequential>

      <antcall target="check.already.defined"/>

      <property name="teamcity.internal.distrib.prep" value="${basedir}/temp/dist_prep"/>
      <property name="teamcity.internal.distrib.prep.agent" value="${teamcity.internal.distrib.prep}/agent"/>
      <property name="teamcity.internal.distrib.prep.common" value="${teamcity.internal.distrib.prep}/common"/>
      <property name="teamcity.internal.distrib.prep.server.resources" value="${teamcity.internal.distrib.prep}/server_resources"/>
      <property name="teamcity.internal.distrib.prep.agent.jars" value="${teamcity.internal.distrib.prep.agent}/unpacked"/>


      <!-- build jars -->

      <delete dir="@{out.unpacked}" quiet="true"/>
      <delete dir="${teamcity.internal.distrib.prep}" quiet="true"/>

      <mkdir dir="@{out.unpacked}"/>

      <condition property="common.needed">
        <length string="@{common.output}" when="greater" length="0"/>
      </condition>
      <condition property="server.needed">
        <or>
          <length string="@{server.output}" when="greater" length="0"/>
          <length string="@{server.resources}" when="greater" length="0"/>
        </or>
      </condition>
      <condition property="server.output.needed">
          <length string="@{server.output}" when="greater" length="0"/>
      </condition>
      <condition property="server.resources.needed">
          <length string="@{server.resources}" when="greater" length="0"/>
      </condition>

      <condition property="agent.needed">
        <length string="@{agent.output}" when="greater" length="0"/>
      </condition>

      <condition property="plugin.descriptor.file.needed">
        <and>
          <available file="@{plugin.descriptor.file}"/>
          <length string="@{plugin.descriptor.file}" when="greater" length="0"/>
        </and>
      </condition>

      <mkdir dir="${teamcity.internal.distrib.prep.common}"/>
      <antcall target="prepare.common.part">
        <param name="common.output" value="@{common.output}"/>
        <param name="common.jar.path" value="${teamcity.internal.distrib.prep.common}/@{common.jar.name}"/>
      </antcall>

      <antcall target="prepare.server.part">
        <param name="out.unpacked" value="@{out.unpacked}"/>
        <param name="name" value="@{name}"/>
        <param name="server.output" value="@{server.output}"/>
        <param name="server.resources" value="@{server.resources}"/>
        <param name="common.jar.path" value="${teamcity.internal.distrib.prep.common}/@{common.jar.name}"/>
        <param name="lib.dir" value="@{server.lib.dir}"/>
        <param name="lib.includes" value="@{server.lib.includes}"/>
      </antcall>

      <antcall target="prepare.agent.part">
        <param name="out.unpacked" value="@{out.unpacked}"/>
        <param name="name" value="@{name}"/>
        <param name="agent.output" value="@{agent.output}"/>
        <param name="common.jar.path" value="${teamcity.internal.distrib.prep.common}/@{common.jar.name}"/>
      </antcall>

      <!-- copy additional agent files -->
      <mkdir dir="${teamcity.internal.distrib.prep.agent.jars}/@{name}" />
      <copy todir="${teamcity.internal.distrib.prep.agent.jars}/@{name}">
        <fileset dir="${basedir}" excludes="**"/>
        <agent-additional-files/>
      </copy>

      <antcall target="pack.agent.part">
        <param name="out.unpacked" value="@{out.unpacked}"/>
        <param name="name" value="@{name}"/>
      </antcall>

      <!-- copy teamcity-plugin.xml -->
      <antcall target="prepare.plugin.descriptor.file">
        <param name="source" value="@{plugin.descriptor.file}"/>
        <param name="dest" value="@{out.unpacked}/teamcity-plugin.xml"/>
        <param name="plugin.version" value="@{plugin.version}"/>
      </antcall>

      <!-- copy additional server plugin files -->
      <copy todir="@{out.unpacked}">
        <fileset dir="${basedir}" excludes="**"/>
        <server-additional-files/>
      </copy>

      <!-- clean -->
      <echo message="Cleaning..."/>
      <delete dir="${teamcity.internal.distrib.prep}" quiet="true"/>

      <!-- package in zip -->
      <echo message="Packaging zip..."/>
      <delete file="@{out}/@{name}.zip" quiet="true"/>
      <zip destfile="@{out}/@{name}.zip">
        <fileset dir="@{out.unpacked}"/>
      </zip>
      <echo message="To install the plugin, place '@{out}\@{name}.zip' into '.BuildServer/plugins' directory"/>

    </sequential>
  </macrodef>

  <target name="check.teamcitydistribution" description="checks whether TeamCity distribution ready to be used by IDEA-generated build">
    <check.property name="path.variable.teamcitydistribution"
                    fail-message="Please define 'teamcity.distribution' or 'path.variable.teamcitydistribution' property (e.g. in build.properties file). The property should point to unpacked TeamCity .tar.gz or .exe distribution."
        />

    <condition property="teamcity.distribution.not.present">
      <not>
        <and>
          <available file="${path.variable.teamcitydistribution}/webapps/ROOT/WEB-INF/lib"/>
        </and>
      </not>
    </condition>
    <fail if="teamcity.distribution.not.present"
          message="Cannot find TeamCity distribution at path '${path.variable.teamcitydistribution}'. The property 'teamcity.distribution' or 'path.variable.teamcitydistribution' should point to unpacked TeamCity .tar.gz or .exe distribution."/>
    <echo message="Using ${path.variable.teamcitydistribution} as TeamCity distribution" />
  </target>

  <macrodef name="deploy.teamcity.plugin">
    <attribute name="name"/>
    <attribute name="teamcity.data.path" default="${teamcity.data.path}" description="path to .BuildServer"/>
    <attribute name="out" default="${teamcity.internal.default.out}" description="directory storing prepared plugin zip"/>

    <sequential>
      <copy file="@{out}/@{name}.zip" todir="@{teamcity.data.path}/plugins" failonerror="true"/>
    </sequential>
  </macrodef>

  <macrodef name="undeploy.teamcity.plugin">
    <attribute name="name"/>
    <attribute name="teamcity.data.path" default="${teamcity.data.path}" description="path to .BuildServer"/>

    <sequential>
      <delete file="@{teamcity.data.path}/plugins/@{name}.zip" quiet="true"/>
    </sequential>
  </macrodef>


  <macrodef name="unpack.teamcity" description="TeamCity distribution unpacking">
    <attribute name="distribution.dir" default="${basedir}/teamcity-dist"
               description="path to put unpacked TeamCity distribution into. Warning: the content of the directory will be deleted!"/>
    <attribute name="teamcity.data.path" default="${user.home}/.BuildServer" description="path to .BuildServer"/>
    <attribute name="teamcity.tar.gz-location" default="${basedir}" description="path where TeamCity-NNNN.tar.gz file resides"/>

    <sequential>
      <delete dir="@{distribution.dir}" quiet="true"/>
      <mkdir dir="@{distribution.dir}"/>

      <!-- TODO: issue error if there are several matching files -->

      <untar compression="gzip" dest="@{distribution.dir}">
        <fileset dir="@{teamcity.tar.gz-location}">
          <include name="*.tar.gz"/>
        </fileset>
      </untar>

      <move todir="@{distribution.dir}">
        <fileset dir="@{distribution.dir}\TeamCity">
          <include name="**"/>
        </fileset>
      </move>
    </sequential>
  </macrodef>


  <!--   ** Implementation **   -->

  <macrodef name="check.property">
    <attribute name="name"/>
    <attribute name="fail-message" default=""/>
    <attribute name="check-path" default=""/>
    <sequential>
      <condition property="is.configured.@{name}">
        <not>
          <and>
            <isset property="@{name}"/>
            <length string="${@{name}}" when="greater" length="0"/>
          </and>
        </not>
      </condition>
      <fail if="is.configured.@{name}"
            message="Property '@{name}' not defined. @{fail-message}"/>
    </sequential>
  </macrodef>


  <target name="prepare.common.part" if="common.needed">
    <jar destfile="${common.jar.path}">
      <fileset dir="${common.output}"/>
    </jar>
  </target>


  <target name="prepare.server.part" if="server.needed">
    <mkdir dir="${out.unpacked}/server"/>

    <antcall target="prepare.server.part.output"/>
    <antcall target="prepare.server.part.resources"/>

    <copy todir="${out.unpacked}/server" failonerror="false">
      <fileset file="${common.jar.path}"/>
      <fileset dir="${lib.dir}" includes="${lib.includes}"/>
    </copy>
  </target>

  <target name="prepare.server.part.output" if="server.output.needed">
    <jar destfile="${out.unpacked}/server/${name}.jar">
      <fileset dir="${server.output}"/>
    </jar>
  </target>

  <target name="prepare.server.part.resources" if="server.resources.needed">
    <mkdir dir="${teamcity.internal.distrib.prep.server.resources}/buildServerResources"/>
    <copy todir="${teamcity.internal.distrib.prep.server.resources}/buildServerResources">
      <fileset dir="${server.resources}"/>
    </copy>

    <jar destfile="${out.unpacked}/server/${name}.jar" update="true">
      <fileset dir="${teamcity.internal.distrib.prep.server.resources}"/>
    </jar>
  </target>


  <target name="pack.agent.part" if="agent.needed">
    <zip destfile="${out.unpacked}/agent/${name}.zip">
      <fileset dir="${teamcity.internal.distrib.prep.agent.jars}"/>
    </zip>
  </target>

  <target name="prepare.agent.part" if="agent.needed">
    <!-- prepare.agent.part -->
    <mkdir dir="${teamcity.internal.distrib.prep.agent}"/>
    <mkdir dir="${teamcity.internal.distrib.prep.agent.jars}/${name}/lib"/>
    <mkdir dir="${out.unpacked}/agent"/>

    <jar destfile="${teamcity.internal.distrib.prep.agent.jars}/${name}/lib/${name}.jar">
      <fileset dir="${agent.output}"/>
    </jar>

    <copy todir="${teamcity.internal.distrib.prep.agent.jars}/${name}/lib" failonerror="false">
      <fileset file="${common.jar.path}"/>
    </copy>
  </target>

  <target name="prepare.plugin.descriptor.file" if="plugin.descriptor.file.needed">
    <echo message="Copying plugin descriptor file '${source}' to '${dest}'."/>
    <copy file="${source}" tofile="${dest}" failonerror="false"/>

    <echo message="Replacing '@version@' on '${plugin.version}' in the copied plugin descriptor file."/>
    <replace file="${dest}" value="${plugin.version}">
      <replacetoken><![CDATA[@version@]]></replacetoken>
    </replace>
  </target>

  <target name="check.already.defined">
    <condition property="already.defined">
      <isset property="teamcity.internal.distrib.prep"/>
    </condition>
    <fail if="already.defined"
          message="It seems you are trying to use the script several times in the same context. This script does not support such use. Please call this script as a separate Ant process, via 'ant' task."/>
  </target>

</project>